/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: set ts=8 sts=4 et sw=4 tw=99: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */#ifndef vm_TaggedProto_h#define vm_TaggedProto_h#include"gc/Tracer.h"namespacejs{// Information about an object prototype, which can be either a particular// object, null, or a lazily generated object. The latter is only used by// certain kinds of proxies.classTaggedProto{public:staticJSObject*constLazyProto;TaggedProto():proto(nullptr){}TaggedProto(constTaggedProto&other):proto(other.proto){}explicitTaggedProto(JSObject*proto):proto(proto){}uintptr_ttoWord()const{returnuintptr_t(proto);}boolisDynamic()const{returnproto==LazyProto;}boolisObject()const{/* Skip nullptr and LazyProto. */returnuintptr_t(proto)>uintptr_t(TaggedProto::LazyProto);}JSObject*toObject()const{MOZ_ASSERT(isObject());returnproto;}JSObject*toObjectOrNull()const{MOZ_ASSERT(!proto||isObject());returnproto;}JSObject*raw()const{returnproto;}booloperator==(constTaggedProto&other)const{returnproto==other.proto;}booloperator!=(constTaggedProto&other)const{returnproto!=other.proto;}HashNumberhashCode()const;boolhasUniqueId()const;boolensureUniqueId()const;uint64_tuniqueId()const;voidtrace(JSTracer*trc){if(isObject())TraceManuallyBarrieredEdge(trc,&proto,"TaggedProto");}private:JSObject*proto;};template<>structInternalBarrierMethods<TaggedProto>{staticvoidpreBarrier(TaggedProto&proto);staticvoidpostBarrier(TaggedProto*vp,TaggedProtoprev,TaggedProtonext);staticvoidreadBarrier(constTaggedProto&proto);staticboolisMarkable(constTaggedProto&proto){returnproto.isObject();}};template<classWrapper>classWrappedPtrOperations<TaggedProto,Wrapper>{constTaggedProto&value()const{returnstatic_cast<constWrapper*>(this)->get();}public:uintptr_ttoWord()const{returnvalue().toWord();}inlineboolisDynamic()const{returnvalue().isDynamic();}inlineboolisObject()const{returnvalue().isObject();}inlineJSObject*toObject()const{returnvalue().toObject();}inlineJSObject*toObjectOrNull()const{returnvalue().toObjectOrNull();}JSObject*raw()const{returnvalue().raw();}HashNumberhashCode()const{returnvalue().hashCode();}uint64_tuniqueId()const{returnvalue().uniqueId();}};// If the TaggedProto is a JSObject pointer, convert to that type and call |f|// with the pointer. If the TaggedProto is lazy, calls F::defaultValue.template<typenameF,typename...Args>autoDispatchTyped(Ff,constTaggedProto&proto,Args&&...args)->decltype(f(static_cast<JSObject*>(nullptr),mozilla::Forward<Args>(args)...)){if(proto.isObject())returnf(proto.toObject(),mozilla::Forward<Args>(args)...);returnF::defaultValue(proto);}// Since JSObject pointers are either nullptr or a valid object and since the// object layout of TaggedProto is identical to a bare object pointer, we can// safely treat a pointer to an already-rooted object (e.g. HandleObject) as a// pointer to a TaggedProto.inlineHandle<TaggedProto>AsTaggedProto(HandleObjectobj){static_assert(sizeof(JSObject*)==sizeof(TaggedProto),"TaggedProto must be binary compatible with JSObject");returnHandle<TaggedProto>::fromMarkedLocation(reinterpret_cast<TaggedProtoconst*>(obj.address()));}}// namespace js#endif // vm_TaggedProto_h